/* small code samples here are like the ones in fail.e, every test is like
 * a simple program, and the comments are about the debug output
 * (don't expected the entire file to work as input)
 */


/******************************************************************************/
auto a = 1, b = 2, c;
if (a && b)
    c = a;
else
    c = b;
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : b
;  C   : c
;  C   : a
    enter 0 1
    #name "<stdin>" 1
    int 1
    sd a#1
    int 2
    sd b#1
    #line 3
    int 1
    sd c#1
    exit
 */

auto a = 0, b = 1, c;
if (a || b)
    c = a;
else
    c = b;
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : b
;  C   : c
;  C   : a
    enter 0 1
    #name "<stdin>" 1
    int 0
    sd a#1
    int 1
    sd b#1
    #line 3
    int 0
    sd c#1
    exit
 */


/******************************************************************************/
auto a = 3, b;
switch (a) {		// <- all cases are semantically identical
    case 1:		//	and also, 'a' is a constant at the
	b = a;		//	time of the check
	break;
    case 2:
	b = a;
	break;
    case 3:
	b = 3;
	break;
    default:
	b = a;
	break;
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L3 L2 L4 L1 
;  C   : a
;  C   : b
    enter 0 1
    #name "<stdin>" 1
    int 3
    sd a#1
    #line 2
 jh nil:L4 3:L3 1:L1 2:L2 
  j L4
L1:     ;
; stack: 0
;  srcs: nil 
;  dsts: 
;  C   : b
    #line 4
    int 3
    sd b#1
    #line 5
    exit
L2:     ;
; stack: 0
;  srcs: nil 
;  dsts: 
;  C   : b
    #line 7
    int 3
    sd b#2
    #line 8
    exit
L3:     ;
; stack: 0
;  srcs: nil 
;  dsts: 
;  C   : b
    #line 10
    int 3
    sd b#3
    #line 11
    exit
L4:     ;
; stack: 0
;  srcs: nil 
;  dsts: 
;  C   : b
    #line 13
    int 3
    sd b#4
    #line 14
    exit
 */


/******************************************************************************/
auto a, b;
for (a = b = 0; a < 100; ++a)
    b += a;
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : b
;  C   : a
    enter 0 2
    #name "<stdin>" 2
    int 0
    sd b#1
    sd a#1
L1:     ; cyclic
; stack: 0
;  srcs: nil L1 
;  dsts: #<0814c49c> L1 
; LC  Y: b
; LC  Y: a
    #line 3
    ld b#2
    push
    ld a#2
    add
    sd b#3
    ld a#2
    inc
    sd a#3
    push
    int 100
    lt
 jt L1
#<0814c49c>:    ;
; stack: 0
;  srcs: L1 
;  dsts: 
    exit
 */
/* New version with test duplication is better, it reduces the loop body
 * from 14 to 12 vm instructions.
 */

auto a, b;
for (a = b = 0; a < 100; a++)
    b += a;
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : b
;  C   : a
    enter 0 2
    #name "<stdin>" 2
    int 0
    sd b#1
    sd a#1
L1:     ; cyclic
; stack: 0
;  srcs: L1 nil 
;  dsts: #<0814c56c> L1 
; LC  Y: b
; LC  Y: a
    #line 3
    ld b#2
    push
    ld a#2
    add
    sd b#3
    ld a#2
    inc
    sd a#3
    push
    int 100
    lt
 jt L1
#<0814c56c>:    ;
; stack: 0
;  srcs: L1 
;  dsts: 
    exit
 */


/* simple while test */
auto a = 0, b = 0;
while (a < 10)
    b += ++a;
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : a
;  C   : b
    enter 0 2
    #name "<stdin>" 1
    int 0
    sd a#1
    sd b#1
L1:     ; cyclic
; stack: 0
;  srcs: L1 nil 
;  dsts: L1 #<0814c4d4> 
; LC  Y: b
; LC  Y: a
    #line 3
    ld b#2
    push
    ld a#2
    inc
    sd a#3
    add
    sd b#3
    ld a#3
    push
    int 10
    lt
 jt L1
#<0814c4d4>:    ;
; stack: 0
;  srcs: L1 
;  dsts: 
    exit
 */

/******************************************************************************/
auto a, b, c, d;		// values known to be null
if (a) {
    if (b) {
	if (c)
	    d = c;
	else
	    d = b;
    }
    else if (c)
	d = c;
    else
	d = a;
}
else if (b) {
    if (c)
	d = c;
    else
	d = b;
}
else if (c)
    d = c;
else
    d = 0;
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : a
;  C   : c
;  C   : d
;  C   : b
    enter 0 1
    #name "<stdin>" 3
    int 0
    sd d#1
    exit
 */
/* FIXME warnings must be generated due to use of uninitialized symbols */

/* simplified test above, but on a function, because, as the globals
 * are not initialized, the optimization code doesn't know they are
 * in the "just created" state, but on locals, it should optimize the
 * initial null value
 */
void t()
{
    auto a, b, c;
    if (a) {
	if (b)
	    c = b;
	else
	    c = a;
    }
    else if (b)
	c = b;
    else
	c = 0;
}
t();
/*
; stack: 0
;  srcs: 
;  dsts: 
;  C   : c
;  C   : b
;  C   : a
    enter 4 0
    #name "<stdin>" 5
    int 0
    ret
 */
/* there is a known problem here, where the return value is, in this case
 * 0, but no code should depend on it, as the parser still allows the
 * value to be used in some cases */


/******************************************************************************/
/* very simple check of the stack debug information */
auto a, b;
auto fa() { return 1; }
auto fb() { return 2; }
a = fa(), b = fb();
a = b + (a ? a : b);
/* ignoring body of temp functions, defined to avoid constant propagation */
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: #<0814ee94> L1 
;  C   : a
;  C   : b
    enter 0 2
    #name "<stdin>" 4
    call fa
    sd a#1
    call fb
    sd b#1
    #line 5
    push
    ld a#1
 jt L1
#<0814ee94>:    ;
; stack: 0
;  srcs: nil 
;  dsts: L1 
;      : b
    ld b#1
L1:     ;
; stack: 1
;  srcs: nil #<0814ee94> 
;  dsts: 
;  C   : a
    add
    sd a#2
    exit
 */

/******************************************************************************/
auto fa() { return 1; }
auto fb() { return 2; }
auto fc() { return 3; }
auto fd() { return 4; }
auto a = fa(), b = fb(), c = fc(), d = fd(), e, f;
e = a * b + c;
f = a * b + d;
/* ignoring body of temp functions, defined to avoid constant propagation */
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : c
;  C   : d
;  C   : a
;  C   : @0
;  C   : b
;  C   : f
;  C   : e
    enter 1 1
    #name "<stdin>" 5
    call fa
    sd a#1
    call fb
    sd b#1
    call fc
    sd c#1
    call fd
    sd d#1
    #line 6
    ld a#1
    push
    ld b#1
    mul
    sb @0#1
    push
    ld c#1
    add
    sd e#1
    #line 7
    lb @0#1
    push
    ld d#1
    add
    sd f#1
    exit
 */
/* first test/output of cse code, where @0 replaces 'a * b' */


/******************************************************************************/
auto fa() { return 1; }	
auto fb() { return 2; }
auto fc() { return 3; }
auto a = fa(), b = fb(), c = fc(), d, e, f;
d = a + b + c;
e = a + b + c;
f = a + b + c + d;
if (d != 6 || e != 6 || f != 12)	print("error\n");
/* ignoring body of temp functions, defined to avoid constant propagation */
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: #<08153714> L4 
;  C   : a
;  C   : f
;  C   : b
;  C   : e
;  C   : c
;  C   : d
;  C   : @0
    enter 1 1
    #name "<stdin>" 4
    call fa
    sd a#1
    call fb
    sd b#1
    call fc
    sd c#1
    #line 5
    ld a#1
    push
    ld b#1
    add
    push
    ld c#1
    add
    sb @0#1
    sd d#1
    #line 6
    lb @0#1
    sd e#1
    #line 7
    push
    ld d#1
    add
    sd f#1
    #line 8
    ld d#1
    push
    int 6
    ne
 jt L4
#<08153714>:    ;
; stack: 0
;  srcs: nil 
;  dsts: L4 #<081537ec> 
;      : e
    ld e#1
    push
    int 6
    ne
 jt L4
#<081537ec>:    ;
; stack: 0
;  srcs: #<08153714> 
;  dsts: L4 L2 
;      : f
    ld f#1
    push
    int 12
    ne
 jf L2
L4:     ;
; stack: 0
;  srcs: #<08153714> nil #<081537ec> 
;  dsts: L2 
    ll "error\012"
    push
    blt print 1
L2:     ;
; stack: 0
;  srcs: L4 #<081537ec> 
;  dsts: 
    exit
 */
/* test for erem_temp_symbol(), as the cse code should have have created
 * a temporary for 'a + b', and one for 'a + b + c', what caused the
 * first one to never be used */


/******************************************************************************/
auto a = 1.5l, b = 2.5l, c = 3.25l, d;
d = a + b + c;
if (d - 1 != 6.25l)	print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : b
;  C   : a
;  C   : d
;  C   : c
    enter 0 1
    #name "<stdin>" 1
    ll 1.5l
    sd a#1
    ll 2.5l
    sd b#1
    ll 3.25l
    sd c#1
    #line 2
    ll 7.25l
    sd d#1
    int 0
    exit
 */


/******************************************************************************/
auto a, b, c;
c = (a = 1) + (b = 2);
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : a
;  C   : b
;  C   : c
    enter 0 1
    #name "<stdin>" 2
    int 1
    sd a#1
    int 2
    sd b#1
    int 3
    sd c#1
    exit
 */
/* check special handling of constant folding with assignments in the
 * middle of an expression, what could cause incorrect code generation */

/* variant of sample above */
auto a, b, c;
c = (a = 1, 2) + (b = 3, 4 + 5);
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : a
;  C   : b
;  C   : c
    enter 0 1
    #name "<stdin>" 2
    int 1
    sd a#1
    int 3
    sd b#1
    int 11
    sd c#1
    exit
 */

/* another variant of sample above */
auto a, b, c;
c = (a = (1, 2)) + (b = (3, 4 + 5));
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : a
;  C   : b
;  C   : c
    enter 0 1
    #name "<stdin>" 2
    int 2
    sd a#1
    int 9
    sd b#1
    int 11
    sd c#1
    exit
 */


/******************************************************************************/
auto t = 1;
auto i = 1 * t;
auto v[2][2] = { { 0, 1 }, { 2, 3 } };
t = v[i][t];
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : t
;  C E : v
;  C   : i
    enter 0 1
    #name "<stdin>" 1
    int 1
    sd i#1
    #line 3
    ll #void(0 1 2 3)
    sd v#1
    #line 4
    lvx 3
    sd t#1
    exit
 */
/* check that the 'off' is removed and that the 'lv*' is converted to 'lv',
 * that is, after constant folding it can removed the intermediate offset
 * check, and convert the load of runtime value offset to an opcode with
 * compile time known offset
 */

/******************************************************************************/
/* simple test of loop invariant expressions */
/* check that the expression 'n - 1' is loop invariant */
auto i, j, n = 10;
for (i = j = 1; i <= n - 1; i++)
    j += i;
j += n - 1;
if (j != 55)		print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : i
;  C   : n
;  C   : j
    enter 0 2
    #name "<stdin>" 1
    int 10
    sd n#1
    #line 2
    int 1
    sd j#1
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: nil L1 
;  dsts: #<0814f00c> L1 
; LC  Y: i
; LC  Y: j
    #line 3
    ld j#2
    push
    ld i#2
    add
    sd j#3
    ld i#2
    inc
    sd i#3
    push
    int 9
    le
    #line 4
 jt L1
#<0814f00c>:    ;
; stack: 0
;  srcs: L1 
;  dsts: L3 #<0814f0e4> 
; LC  Y: j
    ld j#4
    push
    int 9
    add
    sd j#5
    #line 5
    push
    int 55
    ne
 jf L3
#<0814f0e4>:    ;
; stack: 0
;  srcs: #<0814f00c> 
;  dsts: L3 
    ll "error\012"
    push
    blt print 1
L3:     ;
; stack: 0
;  srcs: #<0814f00c> #<0814f0e4> 
;  dsts: 
    exit
 */

/* same version, now avoiding constant folding and using cse */
auto fn() { return 10; }
auto i, j, n = fn();
for (i = j = 1; i <= n - 1; i++)
    j += i;
j += n - 1;
if (j != 55)		print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 L0 
;  C   : n
;  C   : i
;  C   : j
    enter 0 2
    #name "<stdin>" 2
    call fn
    sd n#1
    #line 3
    int 1
    sd j#1
    sd i#1
    push
    ld n#1
    dec
    le
 jf L0
L1:     ; cyclic
; stack: 0
;  srcs: L1 nil 
;  dsts: L1 L0 
;      : n
; LC  Y: i
; LC  Y: j
    #line 4
    ld j#2
    push
    ld i#2
    add
    sd j#3
    ld i#2
    inc
    sd i#3
    push
    ld n#1
    dec
    le
 jt L1
L0:     ;
; stack: 0
;  srcs: L1 nil 
;  dsts: L3 #<081502f4> 
;      : n
; LC  Y: j
    #line 5
    ld j#4
    push
    ld n#1
    dec
    add
    sd j#5
    #line 6
    push
    int 55
    ne
 jf L3
#<081502f4>:    ;
; stack: 0
;  srcs: L0 
;  dsts: L3 
    ll "error\012"
    push
    blt print 1
L3:     ;
; stack: 0
;  srcs: #<081502f4> L0 
;  dsts: 
    exit
 */

auto a = 1, b = 2, c, d, i, j, k;
c = a + b;
for (i = 0; i < 10; ++i) {
    c = a + b;
    d = c - a;
    if (c != 3 || d != 2)		print("error i\n");
    for (j = 0; j < 10; ++j) {
	c = a + b;
	d = c - b;
	if (c != 3 || d != 1)		print("error j\n");
	for (k = 0; k < 10; ++k) {
	    c = a + b;
	    d = c - a;
	    if (c != 3 || d != 2)	print("error k\n");
	}
    }
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : c
;  C   : j
;  C   : a
;  C   : b
;  C   : d
;  C   : k
;  C   : i
    enter 0 2
    #name "<stdin>" 1
    int 1
    sd a#1
    int 2
    sd b#1
    #line 2
    int 3
    sd c#1
    #line 3
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: #<081698cc> nil 
;  dsts: L6 
;  C  Y: c
;  C  Y: d
;  C  Y: j
    #line 4
    int 3
    sd c#3
    int 2
    sd d#2
    int 0
    sd j#2
L6:     ; cyclic
; stack: 0
;  srcs: #<081697f4> L1 
;  dsts: L11 
;  C  Y: c
;  C  Y: d
;  C  Y: k
    #line 8
    int 3
    sd c#5
    int 1
    sd d#4
    int 0
    sd k#2
L11:    ; cyclic
; stack: 0
;  srcs: L11 L6 
;  dsts: #<081697f4> L11 
;  C  Y: c
;  C  Y: d
; LC  Y: k
    #line 12
    int 3
    sd c#7
    int 2
    sd d#6
    ld k#3
    inc
    sd k#4
    push
    int 10
    lt
 jt L11
#<081697f4>:    ; cyclic
; stack: 0
;  srcs: L11 
;  dsts: #<081698cc> L6 
; LC  Y: j
    ld j#3
    inc
    sd j#4
    push
    int 10
    lt
 jt L6
#<081698cc>:    ; cyclic
; stack: 0
;  srcs: #<081697f4> 
;  dsts: #<081699a4> L1 
; LC  Y: i
    ld i#2
    inc
    sd i#3
    push
    int 10
    lt
 jt L1
#<081699a4>:    ;
; stack: 0
;  srcs: #<081698cc> 
;  dsts: 
    exit
 */

/* variant of above, without the 'print' call, so that it should optimize
 * out the 'c' stores (it must do the stores, unless know that print
 * cannot change it) */
auto a = 1, b = 2, c, d, i, j, k;
c = a + b;
for (i = 0; i < 10; ++i) {
    c = a + b;
    d = c - a;
    for (j = 0; j < 10; ++j) {
	c = a + b;
	d = c - b;
	for (k = 0; k < 10; ++k) {
	    c = a + b;
	    d = c - a;
	}
    }
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : c
;  C   : j
;  C   : a
;  C   : b
;  C   : d
;  C   : k
;  C   : i
    enter 0 2
    #name "<stdin>" 1
    int 1
    sd a#1
    int 2
    sd b#1
    #line 2
    int 3
    sd c#1
    #line 3
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: #<08152a9c> nil 
;  dsts: L4 
;  C  Y: c
;  C  Y: d
;  C  Y: j
    #line 4
    int 3
    sd c#3
    int 2
    sd d#2
    #line 6
    int 0
    sd j#2
L4:     ; cyclic
; stack: 0
;  srcs: #<081529c4> L1 
;  dsts: L7 
;  C  Y: c
;  C  Y: d
;  C  Y: k
    #line 7
    int 3
    sd c#5
    int 1
    sd d#4
    #line 9
    int 0
    sd k#2
L7:     ; cyclic
; stack: 0
;  srcs: L4 L7 
;  dsts: #<081529c4> L7 
;  C  Y: c
;  C  Y: d
; LC  Y: k
    #line 10
    int 3
    sd c#7
    int 2
    sd d#6
    ld k#3
    inc
    sd k#4
    push
    int 10
    lt
 jt L7
#<081529c4>:    ; cyclic
; stack: 0
;  srcs: L7 
;  dsts: #<08152a9c> L4 
; LC  Y: j
    ld j#3
    inc
    sd j#4
    push
    int 10
    lt
 jt L4
#<08152a9c>:    ; cyclic
; stack: 0
;  srcs: #<081529c4> 
;  dsts: #<08152b74> L1 
; LC  Y: i
    ld i#2
    inc
    sd i#3
    push
    int 10
    lt
 jt L1
#<08152b74>:    ;
; stack: 0
;  srcs: #<08152a9c> 
;  dsts: 
    exit
 */

/* variant of above, without constant propagation of 'a' and 'b' */
auto fa() { return 1; }
auto fb() { return 2; }
auto a = fa(), b = fb(), c, d, i, j, k;
c = a + b;
for (i = 0; i < 10; ++i) {
    c = a + b;
    d = c - a;
    if (c != 3 || d != 2)		print("error i\n");
    for (j = 0; j < 10; ++j) {
	c = a + b;
	d = c - b;
	if (c != 3 || d != 1)		print("error j\n");
	for (k = 0; k < 10; ++k) {
	    c = a + b;
	    d = c - a;
	    if (c != 3 || d != 2)	print("error k\n");
	}
    }
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : i
;  C   : j
;  C   : @0
;  C   : k
;  C   : b
;  C   : a
;  C   : c
;  C   : @1
;  C   : d
    enter 2 0
    #name "<stdin>" 3
    call fa
    sd a#1
    call fb
    sd b#1
    #line 4
    ld a#1
    push
    ld b#1
    add
    sb @1#1
    sb @0#1
    sd c#1
    #line 5
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: #<08160624> nil 
;  dsts: #<0815fb04> L15 
;  C  Y: c
;  C  Y: d
;      : @0
;      : a
    #line 6
    lb @0#1
    sd c#3
    #line 7
    push
    ld a#1
    sub
    sd d#2
    #line 8
    lb @0#1
    push
    int 3
    ne
 jt L15
#<0815fb04>:    ; cyclic
; stack: 0
;  srcs: L1 
;  dsts: L4 L15 
;     Y: d
    ld d#3
    push
    int 2
    ne
 jf L4
L15:    ; cyclic
; stack: 0
;  srcs: L1 #<0815fb04> 
;  dsts: L4 
    ll "error i\012"
    push
    blt print 1
L4:     ; cyclic
; stack: 0
;  srcs: L15 #<0815fb04> 
;  dsts: L6 
;  C  Y: j
    #line 9
    int 0
    sd j#2
L6:     ; cyclic
; stack: 0
;  srcs: L4 #<0816054c> 
;  dsts: #<0815fec4> L16 
;  C  Y: c
;      : b
;  C  Y: d
;      : @1
    #line 10
    lb @1#1
    sd c#5
    #line 11
    push
    ld b#1
    sub
    sd d#5
    #line 12
    lb @1#1
    push
    int 3
    ne
 jt L16
#<0815fec4>:    ; cyclic
; stack: 0
;  srcs: L6 
;  dsts: L9 L16 
;     Y: d
    ld d#6
    push
    int 1
    ne
 jf L9
L16:    ; cyclic
; stack: 0
;  srcs: #<0815fec4> L6 
;  dsts: L9 
    ll "error j\012"
    push
    blt print 1
L9:     ; cyclic
; stack: 0
;  srcs: #<0815fec4> L16 
;  dsts: L11 
;  C  Y: k
    #line 13
    int 0
    sd k#2
L11:    ; cyclic
; stack: 0
;  srcs: L14 L9 
;  dsts: #<08160284> L17 
;  C  Y: c
;  C  Y: d
;      : @1
;      : a
    #line 14
    lb @1#1
    sd c#7
    #line 15
    push
    ld a#1
    sub
    sd d#8
    #line 16
    lb @1#1
    push
    int 3
    ne
 jt L17
#<08160284>:    ; cyclic
; stack: 0
;  srcs: L11 
;  dsts: L14 L17 
;     Y: d
    ld d#9
    push
    int 2
    ne
 jf L14
L17:    ; cyclic
; stack: 0
;  srcs: #<08160284> L11 
;  dsts: L14 
    ll "error k\012"
    push
    blt print 1
L14:    ; cyclic
; stack: 0
;  srcs: #<08160284> L17 
;  dsts: #<0816054c> L11 
; LC  Y: k
    ld k#3
    inc
    sd k#4
    push
    int 10
    lt
 jt L11
#<0816054c>:    ; cyclic
; stack: 0
;  srcs: L14 
;  dsts: #<08160624> L6 
; LC  Y: j
    ld j#3
    inc
    sd j#4
    push
    int 10
    lt
 jt L6
#<08160624>:    ; cyclic
; stack: 0
;  srcs: #<0816054c> 
;  dsts: #<081606fc> L1 
; LC  Y: i
    ld i#2
    inc
    sd i#3
    push
    int 10
    lt
 jt L1
#<081606fc>:    ;
; stack: 0
;  srcs: #<08160624> 
;  dsts: 
    exit
 */

/* now without the 'print' call, so that it should optimize the 'c' stores */
auto fa() { return 1; }
auto fb() { return 2; }
auto a = fa(), b = fb(), c, d, i, j, k;
c = a + b;
for (i = 0; i < 10; ++i) {
    c = a + b;
    d = c - a;
    for (j = 0; j < 10; ++j) {
	c = a + b;
	d = c - b;
	for (k = 0; k < 10; ++k) {
	    c = a + b;
	    d = c - a;
	}
    }
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : i
;  C   : c
;  C   : @0
;  C   : b
;  C   : d
;  C   : a
;  C   : k
;  C   : j
    enter 1 1
    #name "<stdin>" 3
    call fa
    sd a#1
    call fb
    sd b#1
    #line 4
    ld a#1
    push
    ld b#1
    add
    sb @0#1
    sd c#1
    #line 5
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: #<08155754> nil 
;  dsts: L4 
;  C  Y: c
;      : @0
;  C  Y: d
;      : a
;  C  Y: j
    #line 6
    lb @0#1
    sd c#3
    #line 7
    push
    ld a#1
    sub
    sd d#2
    #line 8
    int 0
    sd j#2
L4:     ; cyclic
; stack: 0
;  srcs: #<0815567c> L1 
;  dsts: L7 
;  C  Y: c
;      : @0
;      : b
;  C  Y: d
;  C  Y: k
    #line 9
    lb @0#1
    sd c#5
    #line 10
    push
    ld b#1
    sub
    sd d#4
    #line 11
    int 0
    sd k#2
L7:     ; cyclic
; stack: 0
;  srcs: L4 L7 
;  dsts: #<0815567c> L7 
;  C  Y: c
;      : @0
;  C  Y: d
;      : a
; LC  Y: k
    #line 12
    lb @0#1
    sd c#7
    #line 13
    push
    ld a#1
    sub
    sd d#6
    ld k#3
    inc
    sd k#4
    push
    int 10
    lt
 jt L7
#<0815567c>:    ; cyclic
; stack: 0
;  srcs: L7 
;  dsts: L4 #<08155754> 
; LC  Y: j
    ld j#3
    inc
    sd j#4
    push
    int 10
    lt
 jt L4
#<08155754>:    ; cyclic
; stack: 0
;  srcs: #<0815567c> 
;  dsts: #<0815582c> L1 
; LC  Y: i
    ld i#2
    inc
    sd i#3
    push
    int 10
    lt
 jt L1
#<0815582c>:    ;
; stack: 0
;  srcs: #<08155754> 
;  dsts: 
    exit
 */

/* now a test where it actually cannot propagate constants */
auto a = 1, b = 2, c, d, i, j, k;
c = a + b;
for (i = 0; i < 10; ++i) {
    c = a + b;
    d = c - a;
    if (c != 3 || d != 2)		print("error i\n");
    for (j = 0; j < 10; ++j) {
	c = a + b;
	d = c - b;
	if (c != 3 || d != 1)		print("error j\n");
	for (k = 0; k < 10; ++k) {
	    c = a + b + 1;
	    d = c - a - 1;
	    if (c != 4 || d != 2)	print("error k\n");
	}
    }
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : c
;  C   : j
;  C   : a
;  C   : b
;  C   : d
;  C   : k
;  C   : i
    enter 0 2
    #name "<stdin>" 1
    int 1
    sd a#1
    int 2
    sd b#1
    #line 2
    int 3
    sd c#1
    #line 3
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: nil #<08169a8c> 
;  dsts: L6 
;  C  Y: c
;  C  Y: d
;  C  Y: j
    #line 4
    int 3
    sd c#3
    int 2
    sd d#2
    int 0
    sd j#2
L6:     ; cyclic
; stack: 0
;  srcs: #<081699b4> L1 
;  dsts: L11 
;  C  Y: c
;  C  Y: d
;  C  Y: k
    #line 8
    int 3
    sd c#5
    int 1
    sd d#4
    int 0
    sd k#2
L11:    ; cyclic
; stack: 0
;  srcs: L6 L11 
;  dsts: #<081699b4> L11 
;  C  Y: c
;  C  Y: d
; LC  Y: k
    #line 12
    int 4
    sd c#7
    int 2
    sd d#6
    ld k#3
    inc
    sd k#4
    push
    int 10
    lt
 jt L11
#<081699b4>:    ; cyclic
; stack: 0
;  srcs: L11 
;  dsts: L6 #<08169a8c> 
; LC  Y: j
    ld j#3
    inc
    sd j#4
    push
    int 10
    lt
 jt L6
#<08169a8c>:    ; cyclic
; stack: 0
;  srcs: #<081699b4> 
;  dsts: L1 #<08169b64> 
; LC  Y: i
    ld i#2
    inc
    sd i#3
    push
    int 10
    lt
 jt L1
#<08169b64>:    ;
; stack: 0
;  srcs: #<08169a8c> 
;  dsts: 
    exit
 */
/* this would require loop unrolling of the first iteration to allow reuse
 * of the computation in the 'i' loop in the first 'j' loop iteration */
/* FIXME this ofcourse, before live range optimization is done, in which
 * case the entire program could be deleted (if it knows that 'print'
 * cannot use these globals) */

/* now the previous test without the print calls */
auto a = 1, b = 2, c, d, i, j, k;
c = a + b;
for (i = 0; i < 10; ++i) {
    c = a + b;
    d = c - a;
    for (j = 0; j < 10; ++j) {
	c = a + b;
	d = c - b;
	for (k = 0; k < 10; ++k) {
	    c = a + b + 1;
	    d = c - a - 1;
	}
    }
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : c
;  C   : j
;  C   : a
;  C   : b
;  C   : d
;  C   : k
;  C   : i
    enter 0 2
    #name "<stdin>" 1
    int 1
    sd a#1
    int 2
    sd b#1
    #line 2
    int 3
    sd c#1
    #line 3
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: nil #<08152c3c> 
;  dsts: L4 
;  C  Y: c
;  C  Y: d
;  C  Y: j
    #line 4
    int 3
    sd c#3
    int 2
    sd d#2
    #line 6
    int 0
    sd j#2
L4:     ; cyclic
; stack: 0
;  srcs: L1 #<08152b64> 
;  dsts: L7 
;  C  Y: c
;  C  Y: d
;  C  Y: k
    #line 7
    int 3
    sd c#5
    int 1
    sd d#4
    #line 9
    int 0
    sd k#2
L7:     ; cyclic
; stack: 0
;  srcs: L7 L4 
;  dsts: L7 #<08152b64> 
;  C  Y: c
;  C  Y: d
; LC  Y: k
    #line 10
    int 4
    sd c#7
    int 2
    sd d#6
    ld k#3
    inc
    sd k#4
    push
    int 10
    lt
 jt L7
#<08152b64>:    ; cyclic
; stack: 0
;  srcs: L7 
;  dsts: #<08152c3c> L4 
; LC  Y: j
    ld j#3
    inc
    sd j#4
    push
    int 10
    lt
 jt L4
#<08152c3c>:    ; cyclic
; stack: 0
;  srcs: #<08152b64> 
;  dsts: #<08152d14> L1 
; LC  Y: i
    ld i#2
    inc
    sd i#3
    push
    int 10
    lt
 jt L1
#<08152d14>:    ;
; stack: 0
;  srcs: #<08152c3c> 
;  dsts: 
    exit
 */

/* variant, with constant folding only in the portion of code that
 * invalidates the loop invariant expression */
auto a = 1, b = 2, c, d, i, j, k;
c = a;
for (i = 0; i < 10; ++i) {
    c = a;
    d = b;
    if (c != 1 || d != 2)		print("error i\n");
    for (j = 0; j < 10; ++j) {
	c = a;
	d = c;
	if (c != 1 || d != 1)		print("error j\n");
	for (k = 0; k < 10; ++k) {
	    c = a + 1;
	    d = b + 1;
	    if (c != 2 || d != 3)	print("error k\n");
	}
    }
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : c
;  C   : j
;  C   : a
;  C   : b
;  C   : d
;  C   : k
;  C   : i
    enter 0 2
    #name "<stdin>" 1
    int 1
    sd a#1
    int 2
    sd b#1
    #line 2
    int 1
    sd c#1
    #line 3
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: #<08166394> nil 
;  dsts: L6 
;  C  Y: c
;  C  Y: d
;  C  Y: j
    #line 4
    int 1
    sd c#3
    #line 5
    int 2
    sd d#2
    int 0
    sd j#2
L6:     ; cyclic
; stack: 0
;  srcs: L1 #<081662bc> 
;  dsts: L11 
;  C  Y: c
;  C  Y: d
;  C  Y: k
    #line 8
    int 1
    sd c#5
    #line 9
    sd d#4
    int 0
    sd k#2
L11:    ; cyclic
; stack: 0
;  srcs: L6 L11 
;  dsts: #<081662bc> L11 
;  C  Y: c
;  C  Y: d
; LC  Y: k
    #line 12
    int 2
    sd c#7
    #line 13
    int 3
    sd d#6
    ld k#3
    inc
    sd k#4
    push
    int 10
    lt
 jt L11
#<081662bc>:    ; cyclic
; stack: 0
;  srcs: L11 
;  dsts: L6 #<08166394> 
; LC  Y: j
    ld j#3
    inc
    sd j#4
    push
    int 10
    lt
 jt L6
#<08166394>:    ; cyclic
; stack: 0
;  srcs: #<081662bc> 
;  dsts: L1 #<0816646c> 
; LC  Y: i
    ld i#2
    inc
    sd i#3
    push
    int 10
    lt
 jt L1
#<0816646c>:    ;
; stack: 0
;  srcs: #<08166394> 
;  dsts: 
    exit
 */

/* and without the print call */
auto a = 1, b = 2, c, d, i, j, k;
c = a;
for (i = 0; i < 10; ++i) {
    c = a;
    d = b;
    for (j = 0; j < 10; ++j) {
	c = a;
	d = c;
	for (k = 0; k < 10; ++k) {
	    c = a + 1;
	    d = b + 1;
	}
    }
}
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : c
;  C   : j
;  C   : a
;  C   : b
;  C   : d
;  C   : k
;  C   : i
    enter 0 2
    #name "<stdin>" 1
    int 1
    sd a#1
    int 2
    sd b#1
    #line 2
    int 1
    sd c#1
    #line 3
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: nil #<0815259c> 
;  dsts: L4 
;  C  Y: c
;  C  Y: d
;  C  Y: j
    #line 4
    int 1
    sd c#3
    #line 5
    int 2
    sd d#2
    #line 6
    int 0
    sd j#2
L4:     ; cyclic
; stack: 0
;  srcs: #<081524c4> L1 
;  dsts: L7 
;  C  Y: c
;  C  Y: d
;  C  Y: k
    #line 7
    int 1
    sd c#5
    #line 8
    sd d#4
    #line 9
    int 0
    sd k#2
L7:     ; cyclic
; stack: 0
;  srcs: L4 L7 
;  dsts: #<081524c4> L7 
;  C  Y: c
;  C  Y: d
; LC  Y: k
    #line 10
    int 2
    sd c#7
    #line 11
    int 3
    sd d#6
    ld k#3
    inc
    sd k#4
    push
    int 10
    lt
 jt L7
#<081524c4>:    ; cyclic
; stack: 0
;  srcs: L7 
;  dsts: L4 #<0815259c> 
; LC  Y: j
    ld j#3
    inc
    sd j#4
    push
    int 10
    lt
 jt L4
#<0815259c>:    ; cyclic
; stack: 0
;  srcs: #<081524c4> 
;  dsts: #<08152674> L1 
; LC  Y: i
    ld i#2
    inc
    sd i#3
    push
    int 10
    lt
 jt L1
#<08152674>:    ;
; stack: 0
;  srcs: #<0815259c> 
;  dsts: 
    exit
 */

auto i, j, k = 0, v[2][2] = { { 0, 1 }, { 2, 3 } };
for (i = 0; i < 2; ++i) {
    for (j = 0; j < 2; ++j) {
	k += v[i][j];	// k == 6
	k += v[i][j];	// k == 12
    }
    k += v[i][0];	// k == 14
    k += v[i][1];	// k == 18
    k += v[i][0];	// k == 20
    k += v[i][1];	// k == 24
}
if (k != 24)		print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L1 
;  C   : @0
;  C   : i
;  C   : j
;  C   : k
;  C   : v
    enter 1 3
    #name "<stdin>" 1
    int 0
    sd k#1
    ll #void(0 1 2 3)
    sd v#1
    #line 2
    int 0
    sd i#1
L1:     ; cyclic
; stack: 0
;  srcs: nil #<0815430c> 
;  dsts: L4 
;  C  Y: j
    #line 3
    int 0
    sd j#2
L4:     ; cyclic
; stack: 0
;  srcs: L4 L1 
;  dsts: L4 #<0815430c> 
;  C   : @0
; LC  Y: j
;     Y: i
; LC  Y: k
    #line 4
    ld k#2
    push
    ll #void(0 1 2 3)
    push
    ld i#2
    off 2
    push
    add
    push
    ld j#3
    add
    lv
    sb @0#1
    add
    sd k#3
    #line 5
    push
    lb @0#1
    add
    sd k#4
    ld j#3
    inc
    sd j#4
    push
    int 2
    lt
    #line 7
 jt L4
#<0815430c>:    ; cyclic
; stack: 0
;  srcs: L4 
;  dsts: #<081543e4> L1 
; LC  Y: i
; LC  Y: k
    ld k#5
    push
    ll #void(0 1 2 3)
    push
    ld i#3
    off 2
    push
    add
    lv
    add
    sd k#6
    #line 8
    push
    ll #void(0 1 2 3)
    push
    ld i#3
    off 2
    push
    add
    inc
    lv
    add
    sd k#7
    #line 9
    push
    ll #void(0 1 2 3)
    push
    ld i#3
    off 2
    push
    add
    lv
    add
    sd k#8
    #line 10
    push
    ll #void(0 1 2 3)
    push
    ld i#3
    off 2
    push
    add
    inc
    lv
    add
    sd k#9
    ld i#3
    inc
    sd i#4
    push
    int 2
    lt
    #line 12
 jt L1
#<081543e4>:    ;
; stack: 0
;  srcs: #<0815430c> 
;  dsts: #<081544bc> L6 
;     Y: k
    ld k#10
    push
    int 24
    ne
 jf L6
#<081544bc>:    ;
; stack: 0
;  srcs: #<081543e4> 
;  dsts: L6 
    ll "error\012"
    push
    blt print 1
L6:     ;
; stack: 0
;  srcs: #<081543e4> #<081544bc> 
;  dsts: 
    exit
 */

/******************************************************************************/
/* some vector/record tests */
/* test with basic blocks that have operands on stack */
auto va[] = { 1, 2, 3, 4 };
auto vb[] = { 5, 6, 7, 8 };
auto ia = 1, ib = 2;
auto fi() { return 0; }	// avoid constant propagation (until optimized...)
auto fj() { return 3; }
auto fv()[] { return fi() ? va : vb; }	// avoid constant propagation again
auto fk() { return fj() ? ia : ib; }
auto a = fv()[fk()];
if (a != 6)					print("error\n");
if ((fi() ? va : vb)[fj() ? ia : ib] != 6)	print("error\n");
auto b = (!fi() ? va : vb)[!fj() ? ia : ib];
if (b != 3)					print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L0 #<081579ac> 
;  C   : a
;  C   : b
;  C   : va
;  C   : ib
;  C   : ia
;  C   : vb
    enter 0 2
    #name "<stdin>" 1
    ll #void(1 2 3 4)
    sd va#1
    #line 2
    ll #void(5 6 7 8)
    sd vb#1
    #line 3
    int 1
    sd ia#1
    int 2
    sd ib#1
    #line 8
    call fv
    push
    call fk
    lv
    sd a#1
    #line 9
    push
    int 6
    ne
 jf L0
#<081579ac>:    ;
; stack: 0
;  srcs: nil 
;  dsts: L0 
    ll "error\012"
    push
    blt print 1
L0:     ;
; stack: 0
;  srcs: nil #<081579ac> 
;  dsts: L1 #<08157b7c> 
    #line 10
    call fi
 jf L1
#<08157b7c>:    ;
; stack: 0
;  srcs: L0 
;  dsts: L2 
;      : va
    ld va#2
  j L2
L1:     ;
; stack: 0
;  srcs: L0 
;  dsts: L2 
;      : vb
    ld vb#2
L2:     ;
; stack: 0
;  srcs: L1 #<08157b7c> 
;  dsts: #<08157e44> L3 
    push
    call fj
 jf L3
#<08157e44>:    ;
; stack: 0
;  srcs: L2 
;  dsts: L4 
;      : ia
    ld ia#2
  j L4
L3:     ;
; stack: 1
;  srcs: L2 
;  dsts: L4 
;      : ib
    ld ib#2
L4:     ;
; stack: 1
;  srcs: #<08157e44> L3 
;  dsts: #<0815810c> L5 
    lv
    push
    int 6
    ne
 jf L5
#<0815810c>:    ;
; stack: 0
;  srcs: L4 
;  dsts: L5 
    ll "error\012"
    push
    blt print 1
L5:     ;
; stack: 0
;  srcs: #<0815810c> L4 
;  dsts: L6 #<081582dc> 
    #line 11
    call fi
    not
 jf L6
#<081582dc>:    ;
; stack: 0
;  srcs: L5 
;  dsts: L7 
;      : va
    ld va#3
  j L7
L6:     ;
; stack: 0
;  srcs: L5 
;  dsts: L7 
;      : vb
    ld vb#3
L7:     ;
; stack: 0
;  srcs: L6 #<081582dc> 
;  dsts: #<081585a4> L8 
    push
    call fj
    not
 jf L8
#<081585a4>:    ;
; stack: 0
;  srcs: L7 
;  dsts: L9 
;      : ia
    ld ia#3
  j L9
L8:     ;
; stack: 1
;  srcs: L7 
;  dsts: L9 
;      : ib
    ld ib#3
L9:     ;
; stack: 1
;  srcs: #<081585a4> L8 
;  dsts: #<0815886c> L10 
;  C   : b
    lv
    sd b#2
    #line 12
    push
    int 3
    ne
 jf L10
#<0815886c>:    ;
; stack: 0
;  srcs: L9 
;  dsts: L10 
    ll "error\012"
    push
    blt print 1
L10:    ;
; stack: 0
;  srcs: L9 #<0815886c> 
;  dsts: 
    exit
 */

/* check handling of shared objects */
auto v[][] = { { 0, 1 }, { 2, 3 } };
auto v0[] = v[0];
auto v01 = v[0][1];
v0[1] = "one";
if (v[0][1] != v0[1])		print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: #<0814d18c> L0 
;  C   : v01
;  C E : v
;  C E : v0
;  C E : @0
    enter 1 1
    #name "<stdin>" 1
    ll #void(#void(0 1) #void(2 3))
    sd v#1
    #line 2
    lvx 0
    sb @0#1
    sd v0#1
    #line 3
    lb @0#1
    lvx 1
    sd v01#1
    #line 4
    ll "one"
    push
    ld v0#1
    svx 1
    #line 5
    ld v#2
    lvx 0
    lvx 1
    push
    ld v0#2
    lvx 1
    ne
 jf L0
#<0814d18c>:    ;
; stack: 0
;  srcs: nil 
;  dsts: L0 
    ll "error\012"
    push
    blt print 1
L0:     ;
; stack: 0
;  srcs: nil #<0814d18c> 
;  dsts: 
    exit
 */

auto v[] = { 0, 1, 2, 3 };
struct s_t { auto v[]; auto k; } s = { k: '2' };
s.v = v;
v[2] = "two";
if (s.v[2] != v[2])	print("error\n");
s.v[2] = s.k;
if (s.v[2] != v[2])	print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L0 #<0814e284> 
;  C E : v
;  C E : s
    enter 0 2
    #name "<stdin>" 1
    ll #void(0 1 2 3)
    sd v#1
    #line 2
    ll #r(s_t #<0814ae84>)
    sd s#1
    #line 3
    ll #void(0 1 2 3)
    push
    ll #r(s_t #<0814ae84>)
    sr 35 0 0
    #line 4
    ll "two"
    push
    ld v#2
    svx 2
    #line 5
    ld s#2
    lr 35 0 0
    lvx 2
    push
    ld v#3
    lvx 2
    ne
 jf L0
#<0814e284>:    ;
; stack: 0
;  srcs: nil 
;  dsts: L0 
    ll "error\012"
    push
    blt print 1
L0:     ;
; stack: 0
;  srcs: nil #<0814e284> 
;  dsts: L1 #<0814e454> 
;    E : v
;    E : s
    #line 6
    ld s#3
    lr 35 4 0
    push
    ld s#3
    lr 35 0 0
    svx 2
    #line 7
    ld s#4
    lr 35 0 0
    lvx 2
    push
    ld v#4
    lvx 2
    ne
 jf L1
#<0814e454>:    ;
; stack: 0
;  srcs: L0 
;  dsts: L1 
    ll "error\012"
    push
    blt print 1
L1:     ;
; stack: 0
;  srcs: L0 #<0814e454> 
;  dsts: 
    exit
 */

/* check changes in a function */
auto v[] = { 0, 1, 2, 3 };
struct s_t { auto v[]; auto k; } s = { k: '2' };
void set_s_v() { s.v = v; }
void set_v2() { v[2] = "two"; }
auto v2 = v[2];
set_s_v();
auto sv2 = s.v[2];
set_v2();
v[2] = s.k;
if (sv2 != v2 || sv2 == s.v[2] || v2 == v[2] || s.v[2] != v[2])
    print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L6 #<081518ac> 
;  C E : s
;  C   : @0
;  C   : v
;  C   : @1
;  C   : sv2
;  C   : v2
    enter 2 1
    #name "<stdin>" 1
    ll #void(0 1 2 3)
    sd v#1
    #line 2
    ll #r(s_t #<0814ae84>)
    sd s#1
    #line 5
    ll #void(0 1 2 3)
    lvx 2
    sd v2#1
    #line 6
    call set_s_v
    #line 7
    ld s#2
    lr 35 0 0
    lvx 2
    sd sv2#2
    #line 8
    call set_v2
    #line 9
    ld s#3
    lr 35 4 0
    push
    ld v#2
    svx 2
    #line 10
    ld sv2#3
    push
    ld v2#2
    ne
 jt L6
#<081518ac>:    ;
; stack: 0
;  srcs: nil 
;  dsts: #<08151984> L6 
;    E : s
;      : sv2
;  C   : @1
    ld sv2#3
    push
    ld s#4
    lr 35 0 0
    lvx 2
    sb @1#1
    eq
 jt L6
#<08151984>:    ;
; stack: 0
;  srcs: #<081518ac> 
;  dsts: #<08151a5c> L6 
;      : v2
;    E : v
;  C   : @0
    ld v2#2
    push
    ld v#3
    lvx 2
    sb @0#1
    eq
 jt L6
#<08151a5c>:    ;
; stack: 0
;  srcs: #<08151984> 
;  dsts: L6 L3 
;      : @1
;      : @0
    lb @1#1
    push
    lb @0#1
    ne
    #line 11
 jf L3
L6:     ;
; stack: 0
;  srcs: #<08151a5c> #<08151984> nil #<081518ac> 
;  dsts: L3 
    ll "error\012"
    push
    blt print 1
L3:     ;
; stack: 0
;  srcs: #<08151a5c> L6 
;  dsts: 
    exit
 */


/******************************************************************************/
/* cause basic live variable/expression analysis to trigger */
auto f() {}
auto a[] = { 0, 1, 2, 3 };
a[0];	// load merged with assign
f();	// force it to reload 'a'
a[1] + a[2];
a[3];
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : a
    enter 0 1
    #name "<stdin>" 2
    ll #void(0 1 2 3)
    sd a#1
    call f
    #line 6
    ll #void(0 1 2 3)
    lvx 3
    exit
 */

auto fa() { return 0; }
auto fb() { return 1; }
auto fc() { return 2; }
auto a = fa(), b = fb(), c = fc();
a + b + c;
b + c + a;
c + a + b;
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : b
;  C   : a
;  C   : c
    enter 0 2
    #name "<stdin>" 4
    call fa
    sd a#1
    call fb
    sd b#1
    call fc
    sd c#1
    #line 7
    push
    ld a#1
    add
    push
    ld b#1
    add
    exit
*/

auto a[] = { 0, 1, 2, 3 };
a[0] + a[1];
a[1] + a[2];
a[2] + a[3];
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C E : a
    enter 0 2
    #name "<stdin>" 1
    ll #void(0 1 2 3)
    sd a#1
    #line 4
    lvx 2
    push
    ll #void(0 1 2 3)
    lvx 3
    add
    exit
*/

auto a[] = { 0, 1, 2, 3 };
struct s_t { int32_t i; auto a; } s = { 10, 20 };
a[0] + s.i;
s.a + a[1];
a[2] + s.a;
s.i + a[3];
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : a
;  C E : s
    enter 0 2
    #name "<stdin>" 1
    ll #void(0 1 2 3)
    sd a#1
    #line 2
    ll #r(s_t #<0814a3b4>)
    sd s#1
    #line 6
    lr 35 0 23
    push
    ll #void(0 1 2 3)
    lvx 3
    add
    exit
 */


/******************************************************************************/
/* basic post inc/dec conversion check */
auto f() {}
auto a[] = { 0, 1, 2, 3 };
f();	 /* prevent fold of store and load of a */
a[0]++;
a[1]++;
a[2]++;
struct s_t { auto n; } s = { 1 };
f();	/* prevent fold of store and load of s */
s.n++;
if (s.n != 2 || a[0] != 1 || a[1] != 2 || a[2] != 3)
    print("error %d %d %d %d\n", s.n, a[0], a[1], a[2]);
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L6 #<081528f4> 
;  C   : @0
;  C E : a
;  C E : s
    enter 1 5
    #name "<stdin>" 2
    ll #void(0 1 2 3)
    sd a#1
    #line 3
    call f
    #line 4
    ll #void(0 1 2 3)
    lvx 0
    inc
    push
    ll #void(0 1 2 3)
    svx 0
    #line 5
    ld a#2
    lvx 1
    inc
    push
    ld a#2
    svx 1
    #line 6
    ld a#3
    lvx 2
    inc
    push
    ld a#3
    svx 2
    #line 7
    ll #r(s_t #<0814bec4>)
    sd s#2
    #line 8
    call f
    #line 9
    ll #r(s_t #<0814bec4>)
    lr 35 0 0
    inc
    push
    ll #r(s_t #<0814bec4>)
    sr 35 0 0
    #line 10
    ld s#3
    lr 35 0 0
    sb @0#1
    push
    int 2
    ne
 jt L6
#<081528f4>:    ;
; stack: 0
;  srcs: nil 
;  dsts: L6 #<081529cc> 
;    E : a
    ld a#4
    lvx 0
    push
    int 1
    ne
 jt L6
#<081529cc>:    ;
; stack: 0
;  srcs: #<081528f4> 
;  dsts: #<08152aa4> L6 
;    E : a
    ld a#4
    lvx 1
    push
    int 2
    ne
 jt L6
#<08152aa4>:    ;
; stack: 0
;  srcs: #<081529cc> 
;  dsts: L6 L3 
;    E : a
    ld a#4
    lvx 2
    push
    int 3
    ne
    #line 11
 jf L3
L6:     ;
; stack: 0
;  srcs: #<08152aa4> nil #<081529cc> #<081528f4> 
;  dsts: L3 
;      : @0
;    E : a
    begin 4
    ll "error %d %d %d %d\012"
    push
    lb @0#1
    ss -2
    ld a#4
    lvx 0
    ss -3
    ld a#4
    lvx 1
    ss -4
    ld a#4
    lvx 2
    ss -5
    blt print 5
L3:     ;
; stack: 0
;  srcs: #<08152aa4> L6 
;  dsts: 
    exit
 */

/* function version of the above, without call to f(), and without
 * load of constants, to check if it can properly handle store with
 * implicit load */
void test() {
    auto a[] = { 0, 1, 2, 3 };
    a[0]++;
    a[1]++;
    a[2]++;
    struct s_t { auto n; } s = { 1 };
    s.n++;
    if (s.n != 2 || a[0] != 1 || a[1] != 2 || a[2] != 3)
	print("error %d %d %d %d\n", s.n, a[0], a[1], a[2]);
}
test();
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: L7 #<08150974> 
;  C   : @0
;  C E : a
;  C E : s
    enter 4 2
    #name "<stdin>" 2
    vnewx 536870912 16
    push
    ll #void(0 1 2 3)
    vmv 16
    sb a#2
    #line 3
    lvx 0
    inc
    push
    lb a#2
    svx 0
    #line 4
    lb a#3
    lvx 1
    inc
    push
    lb a#3
    svx 1
    #line 5
    lb a#4
    lvx 2
    pushvar
    inc
    push
    lb a#4
    svx 2
    pop
    #line 6
    newx 35 4
    push
    ll #r(s_t #<0814c8cc>)
    mv 4
    sb s#2
    #line 7
    lr 35 0 0
    inc
    push
    lb s#2
    sr 35 0 0
    #line 8
    lb s#3
    lr 35 0 0
    sb @0#1
    push
    int 2
    ne
 jt L7
#<08150974>:    ;
; stack: 0
;  srcs: nil 
;  dsts: #<08150a4c> L7 
;    E : a
    lb a#5
    lvx 0
    push
    int 1
    ne
 jt L7
#<08150a4c>:    ;
; stack: 0
;  srcs: #<08150974> 
;  dsts: #<08150b24> L7 
;    E : a
    lb a#5
    lvx 1
    push
    int 2
    ne
 jt L7
#<08150b24>:    ;
; stack: 0
;  srcs: #<08150a4c> 
;  dsts: L7 L4 
;    E : a
    lb a#5
    lvx 2
    push
    int 3
    ne
    #line 9
 jf L4
L7:     ;
; stack: 0
;  srcs: #<08150a4c> #<08150974> nil #<08150b24> 
;  dsts: L4 
;      : @0
;    E : a
    begin 4
    ll "error %d %d %d %d\012"
    push
    lb @0#1
    ss -2
    lb a#5
    lvx 0
    ss -3
    lb a#5
    lvx 1
    ss -4
    lb a#5
    lvx 2
    ss -5
    blt print 5
L4:     ;
; stack: 0
;  srcs: #<08150b24> L7 
;  dsts: 
    ret
 */

/******************************************************************************/
/* basic strength reduce / simplification test */
auto f() { return 1; }
auto a = f(), b, c = 0;
/* avoid live variable analysis removing intermediate assignments to 'b' */
auto g(v) { ++c; if (b != v) print("error %d %d %d\n", c, b, v); a = b = 1; }
b = a + 1;	g(2);
b = a + 1.0;	g(2);
b = a + 1.0L;	g(2);
b = a - 1;	g(0);
b = a - 1.0;	g(0);
b = a - 1.0L;	g(0);
b = a * 1;	g(1);
b = a * 1.0;	g(1);
b = a * 1.0L;	g(1);
b = a / 1;	g(1);
b = a / 1.0;	g(1);
b = a / 1.0L;	g(1);
b = a * -1;	g(-1);
b = a * -1.0;	g(-1);
b = a * -1.0L;	g(-1);
b = a / -1;	g(-1);
b = a / -1.0;	g(-1);
b = a / -1.0L;	g(-1);
b = a * 0;	g(0);
b = a * 0.0;	g(0);
b = a * 0.0L;	g(0);
b = 1 + a;	g(2);
b = 1.0 + a;	g(2);
b = 1.0L + a;	g(2);
b = 1 * a;	g(1);
b = 1.0 * a;	g(1);
b = 1.0L * a;	g(1);
b = -1 * a;	g(-1);
b = -1.0 * a;	g(-1);
b = -1.0L * a;	g(-1);
b = 1 / a;	g(1);
b = 1.0 / a;	g(1);
b = 1.0L / a;	g(1);
b = 1 - a;	g(0);
b = 1.0 - a;	g(0);
b = 1.0L - a;	g(0);
b = -1 - a;	g(-2);
b = -1.0 - a;	g(-2);
b = -1.0L - a;	g(-2);
b = 0 / a;	g(0);
b = 0.0 / a;	g(0);
b = 0.0L / a;	g(0);
b = a * 2;	g(2);
b = a * 2.0;	g(2);
b = a * 2.0L;	g(2);
b = a + 2;	g(3);
b = a + 2.0;	g(3);
b = a + 2.0L;	g(3);
b = a + -2;	g(-1);
b = a + -2.0;	g(-1);
b = a + -2.0L;	g(-1);
b = a - 2;	g(-1);
b = a - 2.0;	g(-1);
b = a - 2.0L;	g(-1);
b = a - -2;	g(3);
b = a - -2.0;	g(3);
b = a - -2.0L;	g(3);
b = 2 + a;	g(3);
b = 2.0 + a;	g(3);
b = 2.0L + a;	g(3);
b = 0 + a;	g(1);
b = 0.0 + a;	g(1);
b = 0.0L + a;	g(1);
b = -2 + a;	g(-1);
b = -2.0 + a;	g(-1);
b = -2.0L + a;	g(-1);
b = 0 - a;	g(-1);
b = 0.0 - a;	g(-1);
b = 0.0L - a;	g(-1);
b = 0 * a;	g(0);
b = 0.0 * a;	g(0);
b = 0.0L * a;	g(0);
b = a & 0;	g(0);
b = a & -1;	g(1);
b = 0 & a;	g(0);
b = -1 & a;	g(1);
b = a | 0;	g(1);
b = a | -1;	g(-1);
b = 0 | a;	g(1);
b = -1 | a;	g(-1);
b = a ^ -1;	g(-2);
b = -1 ^ a;	g(-2);
b = a / (1/7);	g(7);
b = a \ 1;	g(1);
b = a \ 1.0;	g(1);
b = a \ 1.0L;	g(1);
b = a % 1;	g(0);
b = a % 1.0;	g(0.0);
b = a % 1.0L;	g(0.0L);
b = a \ -1;	g(-1);
b = a \ -1.0;	g(-1);
b = a \ -1.0L;	g(-1);
b = a % -1;	g(0);
b = a % -1.0;	g(0.0);
b = a % -1.0L;	g(0.0L);
b = 2 * a;	g(2);
b = 2.0 * a;	g(2);
b = 2.0L * a;	g(2);
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : b
;  C   : c
;  C   : a
    enter 0 2
    #name "<stdin>" 2
    call f
    sd a#1
    int 0
    sd c#1
    #line 5
    ld a#1
    inc
    sd b#1
    int 2
    pushvar
    call g
    #line 6
    ld a#2
    inc
    sd b#3
    int 2
    pushvar
    call g
    #line 7
    ld a#3
    inc
    sd b#5
    int 2
    pushvar
    call g
    #line 8
    ld a#4
    dec
    sd b#7
    int 0
    pushvar
    call g
    #line 9
    ld a#5
    dec
    sd b#9
    int 0
    pushvar
    call g
    #line 10
    ld a#6
    dec
    sd b#11
    int 0
    pushvar
    call g
    #line 11
    ld a#7
    nump&noop
    sd b#13
    int 1
    pushvar
    call g
    #line 12
    ld a#8
    nump&noop
    sd b#15
    int 1
    pushvar
    call g
    #line 13
    ld a#9
    nump&noop
    sd b#17
    int 1
    pushvar
    call g
    #line 14
    ld a#10
    nump&noop
    sd b#19
    int 1
    pushvar
    call g
    #line 15
    ld a#11
    nump&noop
    sd b#21
    int 1
    pushvar
    call g
    #line 16
    ld a#12
    nump&noop
    sd b#23
    int 1
    pushvar
    call g
    #line 17
    ld a#13
    neg
    sd b#25
    int -1
    pushvar
    call g
    #line 18
    ld a#14
    neg
    sd b#27
    int -1
    pushvar
    call g
    #line 19
    ld a#15
    neg
    sd b#29
    int -1
    pushvar
    call g
    #line 20
    ld a#16
    neg
    sd b#31
    int -1
    pushvar
    call g
    #line 21
    ld a#17
    neg
    sd b#33
    int -1
    pushvar
    call g
    #line 22
    ld a#18
    neg
    sd b#35
    int -1
    pushvar
    call g
    #line 23
    ld a#19
    push
    int 0
    mul
    sd b#37
    int 0
    pushvar
    call g
    #line 24
    ld a#20
    push
    float 0.0
    mul
    sd b#39
    int 0
    pushvar
    call g
    #line 25
    ld a#21
    push
    ll 0.0l
    mul
    sd b#41
    int 0
    pushvar
    call g
    #line 26
    ld a#22
    inc
    sd b#43
    int 2
    pushvar
    call g
    #line 27
    ld a#23
    inc
    sd b#45
    int 2
    pushvar
    call g
    #line 28
    ld a#24
    inc
    sd b#47
    int 2
    pushvar
    call g
    #line 29
    ld a#25
    nump&noop
    sd b#49
    int 1
    pushvar
    call g
    #line 30
    ld a#26
    nump&noop
    sd b#51
    int 1
    pushvar
    call g
    #line 31
    ld a#27
    nump&noop
    sd b#53
    int 1
    pushvar
    call g
    #line 32
    ld a#28
    neg
    sd b#55
    int -1
    pushvar
    call g
    #line 33
    ld a#29
    neg
    sd b#57
    int -1
    pushvar
    call g
    #line 34
    ld a#30
    neg
    sd b#59
    int -1
    pushvar
    call g
    #line 35
    ld a#31
    inv
    sd b#61
    int 1
    pushvar
    call g
    #line 36
    ld a#32
    inv
    sd b#63
    int 1
    pushvar
    call g
    #line 37
    ld a#33
    inv
    sd b#65
    int 1
    pushvar
    call g
    #line 38
    ld a#34
    neg
    inc
    sd b#67
    int 0
    pushvar
    call g
    #line 39
    ld a#35
    neg
    inc
    sd b#69
    int 0
    pushvar
    call g
    #line 40
    ld a#36
    neg
    inc
    sd b#71
    int 0
    pushvar
    call g
    #line 41
    ld a#37
    neg
    dec
    sd b#73
    int -2
    pushvar
    call g
    #line 42
    ld a#38
    neg
    dec
    sd b#75
    int -2
    pushvar
    call g
    #line 43
    ld a#39
    neg
    dec
    sd b#77
    int -2
    pushvar
    call g
    #line 44
    int 0
    push
    ld a#40
    div
    sd b#79
    int 0
    pushvar
    call g
    #line 45
    float 0.0
    push
    ld a#41
    div
    sd b#81
    int 0
    pushvar
    call g
    #line 46
    ll 0.0l
    push
    ld a#42
    div
    sd b#83
    int 0
    pushvar
    call g
    #line 47
    ld a#43
    push
    add
    sd b#85
    int 2
    pushvar
    call g
    #line 48
    ld a#44
    push
    add
    sd b#87
    int 2
    pushvar
    call g
    #line 49
    ld a#45
    push
    add
    sd b#89
    int 2
    pushvar
    call g
    #line 50
    ld a#46
    push
    int 2
    add
    sd b#91
    int 3
    pushvar
    call g
    #line 51
    ld a#47
    push
    float 2.0
    add
    sd b#93
    int 3
    pushvar
    call g
    #line 52
    ld a#48
    push
    ll 2.0l
    add
    sd b#95
    int 3
    pushvar
    call g
    #line 53
    ld a#49
    push
    int -2
    add
    sd b#97
    int -1
    pushvar
    call g
    #line 54
    ld a#50
    push
    float -2.0
    add
    sd b#99
    int -1
    pushvar
    call g
    #line 55
    ld a#51
    push
    ll -2.0l
    add
    sd b#101
    int -1
    pushvar
    call g
    #line 56
    ld a#52
    push
    int 2
    sub
    sd b#103
    int -1
    pushvar
    call g
    #line 57
    ld a#53
    push
    float 2.0
    sub
    sd b#105
    int -1
    pushvar
    call g
    #line 58
    ld a#54
    push
    ll 2.0l
    sub
    sd b#107
    int -1
    pushvar
    call g
    #line 59
    ld a#55
    push
    int -2
    sub
    sd b#109
    int 3
    pushvar
    call g
    #line 60
    ld a#56
    push
    float -2.0
    sub
    sd b#111
    int 3
    pushvar
    call g
    #line 61
    ld a#57
    push
    ll -2.0l
    sub
    sd b#113
    int 3
    pushvar
    call g
    #line 62
    int 2
    push
    ld a#58
    add
    sd b#115
    int 3
    pushvar
    call g
    #line 63
    float 2.0
    push
    ld a#59
    add
    sd b#117
    int 3
    pushvar
    call g
    #line 64
    ll 2.0l
    push
    ld a#60
    add
    sd b#119
    int 3
    pushvar
    call g
    #line 65
    int 0
    push
    ld a#61
    add
    sd b#121
    int 1
    pushvar
    call g
    #line 66
    float 0.0
    push
    ld a#62
    add
    sd b#123
    int 1
    pushvar
    call g
    #line 67
    ll 0.0l
    push
    ld a#63
    add
    sd b#125
    int 1
    pushvar
    call g
    #line 68
    int -2
    push
    ld a#64
    add
    sd b#127
    int -1
    pushvar
    call g
    #line 69
    float -2.0
    push
    ld a#65
    add
    sd b#129
    int -1
    pushvar
    call g
    #line 70
    ll -2.0l
    push
    ld a#66
    add
    sd b#131
    int -1
    pushvar
    call g
    #line 71
    int 0
    push
    ld a#67
    sub
    sd b#133
    int -1
    pushvar
    call g
    #line 72
    float 0.0
    push
    ld a#68
    sub
    sd b#135
    int -1
    pushvar
    call g
    #line 73
    ll 0.0l
    push
    ld a#69
    sub
    sd b#137
    int -1
    pushvar
    call g
    #line 74
    int 0
    push
    ld a#70
    mul
    sd b#139
    int 0
    pushvar
    call g
    #line 75
    float 0.0
    push
    ld a#71
    mul
    sd b#141
    int 0
    pushvar
    call g
    #line 76
    ll 0.0l
    push
    ld a#72
    mul
    sd b#143
    int 0
    pushvar
    call g
    #line 77
    ld a#73
    intp&0
    sd b#145
    int 0
    pushvar
    call g
    #line 78
    ld a#74
    intp&noop
    sd b#147
    int 1
    pushvar
    call g
    #line 79
    ld a#75
    intp&0
    sd b#149
    int 0
    pushvar
    call g
    #line 80
    ld a#76
    intp&noop
    sd b#151
    int 1
    pushvar
    call g
    #line 81
    ld a#77
    intp&noop
    sd b#153
    int 1
    pushvar
    call g
    #line 82
    ld a#78
    intp&-1
    sd b#155
    int -1
    pushvar
    call g
    #line 83
    ld a#79
    intp&noop
    sd b#157
    int 1
    pushvar
    call g
    #line 84
    ld a#80
    intp&-1
    sd b#159
    int -1
    pushvar
    call g
    #line 85
    ld a#81
    com
    sd b#161
    int -2
    pushvar
    call g
    #line 86
    ld a#82
    com
    sd b#163
    int -2
    pushvar
    call g
    #line 87
    ld a#83
    push
    int 7
    mul
    sd b#165
    int 7
    pushvar
    call g
    #line 88
    ld a#84
    trunc
    sd b#167
    int 1
    pushvar
    call g
    #line 89
    ld a#85
    trunc
    sd b#169
    int 1
    pushvar
    call g
    #line 90
    ld a#86
    trunc
    sd b#171
    int 1
    pushvar
    call g
    #line 91
    ld a#87
    push
    int 1
    rem
    sd b#173
    int 0
    pushvar
    call g
    #line 92
    ld a#88
    push
    float 1.0
    rem
    sd b#175
    float 0.0
    pushvar
    call g
    #line 93
    ld a#89
    push
    ll 1.0l
    rem
    sd b#177
    ll 0.0l
    pushvar
    call g
    #line 94
    ld a#90
    trunc
    neg
    sd b#179
    int -1
    pushvar
    call g
    #line 95
    ld a#91
    trunc
    neg
    sd b#181
    int -1
    pushvar
    call g
    #line 96
    ld a#92
    trunc
    neg
    sd b#183
    int -1
    pushvar
    call g
    #line 97
    ld a#93
    push
    int -1
    rem
    sd b#185
    int 0
    pushvar
    call g
    #line 98
    ld a#94
    push
    float -1.0
    rem
    sd b#187
    float 0.0
    pushvar
    call g
    #line 99
    ld a#95
    push
    ll -1.0l
    rem
    sd b#189
    ll 0.0l
    pushvar
    call g
    #line 100
    ld a#96
    push
    add
    sd b#191
    int 2
    pushvar
    call g
    #line 101
    ld a#97
    push
    add
    sd b#193
    int 2
    pushvar
    call g
    #line 102
    ld a#98
    push
    add
    sd b#195
    int 2
    pushvar
    call g
    exit
 */


/******************************************************************************/
/* basic check to propagation of value from predicate+set */
auto f() { return 1; }
auto a = f() & 0;
auto b = a + a;
if (b)
    print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : a
;  C   : b
    enter 0 1
    #name "<stdin>" 2
    call f
    intp&0
    sd a#1
    #line 3
    sd b#1
    #line 5
    exit
 */

/* check for precedence change in folding of predicates */
auto f() { return 1; }
auto a = f() % 1;
auto b = a & 0;
if (b)
    print("error\n");
/*
nil:    ;
; stack: 0
;  srcs: 
;  dsts: 
;  C   : a
;  C   : b
    enter 0 2
    #name "<stdin>" 2
    call f
    push
    int 1
    rem
    sd a#1
    #line 3
    intp&0
    sd b#1
    #line 5
    exit
 */
